package com.simple.http.api;

import android.content.Context;

import com.simple.async.Task;
import com.simple.async.TaskExecutor;
import com.simple.async.TaskResult;
import com.simple.http.callback.RequestCallback;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;


public class HttpUtil {

    private final String TAG = HttpUtil.class.getSimpleName();
    private static HttpUtil instance;
    private static Context context;

    public void init(Context context) {
        context = context.getApplicationContext();
        HttpHeader.initHeader(context);
    }

    private HttpUtil() {

    }

    public static HttpUtil getInstance() {
        if (instance == null) {
            synchronized (HttpUtil.class) {
                if (instance == null) {
                    instance = new HttpUtil();
                }
            }
        }
        return instance;
    }

    public void get(String url, HashMap param, RequestCallback callback) {
        TaskExecutor.executeTask(new Task<String>() {
            @Override
            public String doInBackground() {
                return getSync(context, url, param);
            }
        }, new TaskResult<String>() {
            @Override
            public void onPostExecute(String data) {
                callback.onResult(data);
            }
        });
    }

    public void post(String url, HashMap param, RequestCallback callback) {
        TaskExecutor.executeTask(new Task<String>() {
            @Override
            public String doInBackground() {
                return postSync(context, url, param);
            }
        }, new TaskResult<String>() {
            @Override
            public void onPostExecute(String data) {
                callback.onResult(data);
            }
        });
    }

    public void postJson(String url, String json, RequestCallback callback) {
        TaskExecutor.executeTask(new Task<String>() {
            @Override
            public String doInBackground() {
                return postJsonSync(RequestType.POST, url, json);
            }
        }, new TaskResult<String>() {
            @Override
            public void onPostExecute(String data) {
                callback.onResult(data);
            }
        });
    }

    /**
     * get请求
     *
     * @param context
     * @param url
     * @param param
     * @return
     */
    public String getSync(Context context, String url, HashMap param) {
        return request(RequestType.GET, url, param);
    }

    /**
     * post请求
     *
     * @param context
     * @param url
     * @param param
     * @return
     */
    public String postSync(Context context, String url, HashMap param) {
        return request(RequestType.POST, url, param);
    }

    /**
     * post json请求
     *
     * @param type
     * @param url
     * @param json
     * @return
     */
    public String postJsonSync(@RequestType int type, String url, String json) {
        boolean isGet = type == RequestType.GET;
        StringBuilder str = new StringBuilder();
        InputStream inputStream = null;
        HttpURLConnection connection = null;
        try {
            connection = (HttpURLConnection) new URL(url).openConnection();

            connection.setReadTimeout(30 * 1000);
            connection.setConnectTimeout(15 * 1000);
            connection.setRequestMethod(type == RequestType.GET ? "GET" : "POST");

            HashMap<String, String> hashMap = HttpHeader.getHeader();
            for (Map.Entry<String, String> item : hashMap.entrySet()) {
                connection.setRequestProperty(item.getKey(), item.getValue());
            }

            if (type == RequestType.POST) {
                connection.setDoInput(true);// 设置是否从HttpURLConnection输入，默认值为 true
                connection.setDoOutput(true);// 设置是否使用HttpURLConnection进行输出，默认值为 false
            }
            connection.connect();
            if (!isGet) {
                DataOutputStream out = new DataOutputStream(connection
                        .getOutputStream());
                // The URL-encoded contend
                // 正文，正文内容其实跟get的URL中 '? '后的参数字符串一致
                // DataOutputStream.writeBytes将字符串中的16位的unicode字符以8位的字符形式写到流里面
                out.writeBytes(json);
                out.flush();
                out.close();
            }
            if (connection.getResponseCode() == 200) {
                inputStream = connection.getInputStream();
                InputStreamReader in = new InputStreamReader(connection.getInputStream());
                BufferedReader bufferedReader = new BufferedReader(in);
                String readerLine = null;
                while ((readerLine = bufferedReader.readLine()) != null) {
                    str.append(readerLine);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                connection.disconnect();
            }
        }
        return str.toString();
    }

    /**
     * 请求数据
     *
     * @param type
     * @param url
     * @param param
     * @return
     */
    private String request(@RequestType int type, String url, HashMap param) {
        boolean isGet = type == RequestType.GET;
        if (isGet && param != null && param.size() > 0) {
            url += getParamString(true, param);
        }
        StringBuilder str = new StringBuilder();
        InputStream inputStream = null;
        HttpURLConnection connection = null;
        try {
            connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setReadTimeout(30 * 1000);
            connection.setConnectTimeout(15 * 1000);
            connection.setRequestMethod(type == RequestType.GET ? "GET" : "POST");

            HashMap<String, String> hashMap = HttpHeader.getHeader();
            for (Map.Entry<String, String> item : hashMap.entrySet()) {
                connection.setRequestProperty(item.getKey(), item.getValue());
            }

            if (type == RequestType.POST) {
                connection.setDoInput(true);// 设置是否从HttpURLConnection输入，默认值为 true
                connection.setDoOutput(true);// 设置是否使用HttpURLConnection进行输出，默认值为 false
            }
            connection.connect();
            if (!isGet && param != null && param.size() > 0) {
                DataOutputStream out = new DataOutputStream(connection
                        .getOutputStream());
                // The URL-encoded contend
                // 正文，正文内容其实跟get的URL中 '? '后的参数字符串一致
                // DataOutputStream.writeBytes将字符串中的16位的unicode字符以8位的字符形式写到流里面
                out.writeBytes(getParamString(false, param));
                out.flush();
                out.close();
            }
            if (connection.getResponseCode() == 200) {
                inputStream = connection.getInputStream();
                InputStreamReader in = new InputStreamReader(connection.getInputStream());
                BufferedReader bufferedReader = new BufferedReader(in);
                String readerLine = null;
                while ((readerLine = bufferedReader.readLine()) != null) {
                    str.append(readerLine);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                connection.disconnect();
            }
        }
        return str.toString();
    }

    /**
     * 封装参数
     *
     * @param param
     * @return
     */
    private String getParamString(boolean isGet, HashMap param) {
        StringBuilder builder = new StringBuilder();
        if (isGet) {
            builder.append("?");
        }
        int index = 0;
        for (Object key : param.keySet()) {
            String k = key.toString();
            String v = param.get(key).toString();
            if (index > 0) {
                builder.append("&");
            }
            try {
                builder.append(isGet ? k : URLEncoder.encode(k, "UTF-8"));
                builder.append("=");
                builder.append(isGet ? v : URLEncoder.encode(v, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            index = 1;
        }
        return builder.toString();
    }

    /**
     * 传递文件
     *
     * @param actionUrl
     * @param data
     * @param files
     * @throws IOException
     */
    public void postFile(String actionUrl, Map<String, String> data, Map<String, File> files) {
        try {
            String BOUNDARY = java.util.UUID.randomUUID().toString();   //利用系统工具类生成界限符
            String PREFIX = "--", LINEND = "\r\n";
            String MULTIPART_FROM_DATA = "multipart/form-data";
            String CHARSET = "UTF-8";

            URL uri = new URL(actionUrl);
            HttpURLConnection conn = (HttpURLConnection) uri.openConnection();
            conn.setReadTimeout(15 * 1000); // 缓存的最长时间
            conn.setDoInput(true);// 允许输入
            conn.setDoOutput(true);// 允许输出
            conn.setUseCaches(false); // 不允许使用缓存
            conn.setRequestMethod("POST");
            conn.setRequestProperty("connection", "keep-alive");
            conn.setRequestProperty("Charsert", "UTF-8");
            conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA + ";boundary=" + BOUNDARY);
            if (data != null) {
                for (Map.Entry<String, String> entry : data.entrySet()) {
                    String value = entry.getValue();
                    if (value == null) {
                        continue;
                    }
                    conn.setRequestProperty(entry.getKey(), value);
                }
            }

            DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
            InputStream in = null;
            // 发送文件数据
            if (files != null) {
                for (Map.Entry<String, File> file : files.entrySet()) {
                    StringBuilder sb1 = new StringBuilder();
                    sb1.append(PREFIX);
                    sb1.append(BOUNDARY);
                    sb1.append(LINEND);
                    // name是post中传参的键 filename是文件的名称
                    sb1.append("Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getValue().getName() + "\"" + LINEND);
                    sb1.append("Content-Type: application/octet-stream; charset=" + CHARSET + LINEND);
                    sb1.append("Content-Transfer-Encoding: binary" + LINEND);
                    sb1.append(LINEND);
                    outStream.write(sb1.toString().getBytes());
                    InputStream is = new FileInputStream(file.getValue());
                    byte[] buffer = new byte[1024];
                    int len = 0;
                    while ((len = is.read(buffer)) != -1) {
                        outStream.write(buffer, 0, len);
                    }
                    is.close();
                    outStream.write(LINEND.getBytes());
                }

                // 请求结束标志
                byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes();
                outStream.write(end_data);
                outStream.flush();
                // 得到响应码
                int res = conn.getResponseCode();
                if (res == 200) {
                    in = conn.getInputStream();
                    int ch;
                    StringBuilder sb2 = new StringBuilder();
                    while ((ch = in.read()) != -1) {
                        sb2.append((char) ch);
                    }
                }
                outStream.close();

                conn.disconnect();
            }
        } catch (Exception e) {

        }
    }

    public void put(String url, String json, RequestCallback callback) {
        TaskExecutor.executeTask(new Task<String>() {
            @Override
            public String doInBackground() {
                return putSync(url, json);
            }
        }, new TaskResult<String>() {
            @Override
            public void onPostExecute(String data) {
                callback.onResult(data);
            }
        });
    }

    private String putSync(String url, String json) {

        String result = "";
        try {
            URL mUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) mUrl.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setConnectTimeout(15 * 1000);
            conn.setReadTimeout(15 * 1000);
            // PUT请求
            conn.setRequestMethod("PUT");
            conn.setUseCaches(false);
            conn.setInstanceFollowRedirects(true);
            // json格式上传的模式
            conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
            for (Map.Entry<String, String> entry : HttpHeader.getHeader().entrySet()) {
                String value = entry.getValue();
                if (value == null) {
                    continue;
                }
                conn.setRequestProperty(entry.getKey(), value);
            }
            //解决中文乱码
            PrintWriter osw = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), "utf-8"));
            osw.write(json);
            osw.flush();
            osw.close();
            System.out.println(conn.getResponseCode());
            if (conn.getResponseCode() == 200) {
                InputStreamReader isr = new InputStreamReader(conn.getInputStream());
                BufferedReader br = new BufferedReader(isr);
                String inputLine = null;
                while ((inputLine = br.readLine()) != null) {
                    result += inputLine;
                }
                isr.close();
                conn.disconnect();
            } else {
                //如果出错，一定要检查URL对没有！
                BufferedReader br = new BufferedReader(new InputStreamReader((conn.getErrorStream())));
                String jsontxt = br.readLine();
                br.close();
                result = jsontxt;
            }

            conn.disconnect();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return result;
    }
}
